
#if !defined CS_BASE_H
#define CS_BASE_H

#include <map>
#include "RtDefines.h"
#include "RtDebug.h"
#include "RtErrorNetwork.h"
#include "RtTimerWrapper.h"
#include "RtTimeValue.h"
#include "RtInetAddr.h"
#include "RtMessageBlock.h"
#include "RtConnectionInterface.h"
#include "RtUtilTemplates.h"
#include "RtTrace.h"
#include "RtCnSendBuf.h"

using namespace std;

template <class ServerType> class ServerListT;
template <class ServerType> class CConnAcceptorT;
template <class ServerType> class CConnAcceptorSinkT;
template <class ClientType> class CConnConnectorT;

#define STATUS_UNCONNECTED		0x0001
#define STATUS_CONNECTED		0x0002
#define STATUS_DATA_CAN_SEND	0x0003
#define STATUS_NEED_RECONNECT	0x0004

#define SERVER_INSTANCE			0x01
#define CLIENT_INSTANCE			0x02

#define BYTES_TO_ACK_BACK				10240		//ACK back every 10K bytes received
#define SERVER_UNAVAIL_TIMEOUT			300 // in seconds 
#define SERVER_NORMAL_DISCONN_TIMEOUT	90	//120-90=30 seconds	
#define CONN_DISCONNECT_TIMEOUT			30

#define SERVER_CHECK_INTERVAL			5	//5 seconds	

#define INTERVAL1						60	//For Conn-Resp Checking

#define INTERVAL2						30	//For Keep Alive
#define MAX_TIMES_NO_RECV_KA		8		//For Keep Alive or Data recv Checking(MAX_TIMES_NO_RECV_KA*INTERVAL2)

#ifdef RT_USE_OLD_CONN_WRAP

///////////////////////////////////////////
//class CConnBase
///////////////////////////////////////////
class /*RT_API_EXPORT*/ CConnBase : 
	public IRtTransport,				//As a Transport Handle to Upper layer
	public IRtTransportSink,			//As a Sink to TP
	public IRtAcceptorConnectorSink,	//As a ConnectorSink to TP
	public CRtTimerWrapperSink,
	public CRtReferenceControlSingleThreadTimerDelete	//Reference tool
{
public:
	// interface IRtTransport
	//Accept ITransportSink from Upper layer
	virtual RtResult OpenWithSink(IRtTransportSink* aSink)
	{
		m_pITransportSink = aSink; 

		return RT_OK;
	};

	virtual IRtTransportSink* GetSink()
	{
		return m_pITransportSink;
	};

	virtual RtResult SendData(
		CRtMessageBlock &aData, 
		CRtTransportParameter *aPara = NULL) = 0;
	
	virtual RtResult SetOption(
		DWORD aCommand, 
		LPVOID aArg) = 0;

	virtual RtResult GetOption(
		DWORD aCommand, 
		LPVOID aArg) = 0;
	
	virtual RtResult Disconnect(
		RtResult aReason) = 0;

	// interface IRtTransportSink
	virtual void OnReceive(
		CRtMessageBlock &aData,
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL) = 0;

	virtual void OnSend(
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL) = 0;

	virtual void OnDisconnect(
		RtResult aReason,
		IRtTransport *aTrptId) = 0;

	// interface IRtAcceptorConnectorSink
	virtual void OnConnectIndication(
		RtResult aReason,
		IRtTransport *aTrpt,
		IRtAcceptorConnectorId *aRequestId) = 0;
	
	// interface CRtTimerWrapperSink
	virtual void OnTimer(CRtTimerWrapper* aId) = 0;

	// interface IRtReferenceControl
	virtual DWORD AddReference()
	{
		return CRtReferenceControlSingleThreadTimerDelete::AddReference();
	};

	virtual DWORD ReleaseReference()
	{
		return CRtReferenceControlSingleThreadTimerDelete::ReleaseReference();
	};
public:
	CConnBase() 
	{ 
		m_pITransportSink = NULL; 
		m_pITransport = NULL; 

		m_wLastStatus = STATUS_UNCONNECTED;
		m_wStatus = STATUS_UNCONNECTED;

		m_wChannel = 0;

		m_byConnType = CS_CONN_TYPE_NONE;

		m_cType = CRtConnectionManager::CTYPE_NONE;
		m_cBaseType = CRtConnectionManager::CTYPE_NONE;
		m_bPDUNeedACK = FALSE;
	};

	virtual ~CConnBase() 
	{
		m_Timer.Cancel();//Kill timer

		Reset();
	};

	//Local functions
	
	void SetChannel(WORD wChannel)
	{
		m_wChannel = wChannel;
	};

	WORD GetChannel()
	{
		return m_wChannel;
	};

	void SetTPTransport(IRtTransport *pTrans)
	{
		m_pITransport = pTrans;
	};

	IRtTransport* GetTPTransport()
	{
		return m_pITransport.Get();
	};

	void SetCurrStatus(WORD wStatus)
	{
		m_wLastStatus = m_wStatus;
		m_wStatus = wStatus;
	};

	WORD GetCurrStatus()
	{
		return m_wStatus;
	};

	BYTE GetConnType()
	{
		return m_byConnType;
	}
protected:
	void Reset()
	{
		//m_pITransportSink = NULL; 
		if(m_pITransport)
		{
			m_pITransport->Disconnect(RT_OK);
			m_pITransport = NULL; 
		}

		m_wLastStatus = STATUS_UNCONNECTED;
		m_wStatus = STATUS_UNCONNECTED;

		m_wChannel = 0;
	};

protected:
	IRtTransportSink* m_pITransportSink;		//ITransportSink obj from Upper layer
	CRtAutoPtr<IRtTransport> m_pITransport;	//ITransport obj from TP layer
	
	CRtTimerWrapper m_Timer;					//Timer
	CRtTimerWrapper m_UdpConnTimer;			// UDP Conn Timer

	WORD m_wLastStatus;
	WORD m_wStatus;	
	WORD m_wChannel;
	BYTE m_byConnType;

	CRtConnectionManager::CType m_cType;		//Connection Type of this class
	CRtConnectionManager::CType m_cBaseType;	//Base connection type
	BOOL						m_bPDUNeedACK;
	CRtMutexThreadRecursive		m_mutex;
};

///////////////////////////////////////////
//class CRtCnConn
///////////////////////////////////////////
class /*RT_API_EXPORT*/ CRtCnConn : public CConnBase
{
public:
	virtual RtResult SendData(
		CRtMessageBlock &aData, 
		CRtTransportParameter *aPara = NULL);

	virtual RtResult SetOption(
		DWORD aCommand, 
		LPVOID aArg);

	virtual RtResult GetOption(
		DWORD aCommand, 
		LPVOID aArg);

	virtual RtResult Disconnect(
		RtResult aReason);
public:
	virtual void OnReceive(
		CRtMessageBlock &aData,
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);

	virtual void OnSend(
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);

	virtual void OnDisconnect(
		RtResult aReason,
		IRtTransport *aTrptId) = 0;

	virtual void OnTimer(
		CRtTimerWrapper* aId) = 0;

protected:
	//Internal functions	
	virtual RtResult SendKeepAlive();
	virtual RtResult SendConnReq();
	virtual RtResult SendConnResp();
	virtual RtResult SendDisconn(RtResult aReason);
	
	virtual RtResult SendDataFromSendBuf();
	virtual void DoACK(DWORD dwACK);

	virtual void OnRecvConnResp();
	virtual void OnRecvConnReq();
	virtual void OnRecvDisconn();
	virtual void OnRecvKeepAlive();
	virtual void OnRecvRtt(DWORD inTimestamp) { RT_ASSERTE(FALSE); }

	int GetPDUType();

	//Amount number of PDUs have been received, we may do ACK back to peer
// 	virtual void ACK2PeerIfPossiable(CRtMessageBlock &aData);
protected:
	void Reset();
	void Reset4Recv();
public:
	CRtCnConn(DWORD dwMaxSendBufLen);
	virtual ~CRtCnConn();

	void NeedKeepAlive(BOOL bNeedKeepAlive);
	BYTE GetInstanceType()const
	{
		return m_byInstanceType;
	}
protected:
	CRtCnSendBuf m_SendBuf;
	CRtMessageBlock *m_pmbLocData;	//local Data block for Recv
	CRtMessageBlock *m_pmbRecData;	
	CRtMessageBlock *m_pConnReqPDU;	//Keep ConnReq PDU for re-sending

	DWORD m_dwSeq4ACK;				//Seq# to ACK back
	DWORD m_dwCnt4JudgeACK;			//Counter for judging whether need to ACK back

// 	LONGLONG	m_dwLastRecvTick;
// 	LONGLONG	m_dwLastSendTick;
	
	WORD m_continuousIdleTime;
	BOOL m_isDataReceived;
	BOOL m_isDataSent;

	DWORD m_dwPDULen;				//Whole PDU length should be received this time
	BYTE m_byType;					//Type of PDU which is recving
	DWORD m_dwDataLen;				//When recving Data PDU, this indicate content len of the real data

	BOOL m_bNormalDisconn;			//Is normal disconnect
	BOOL m_bNoRoom;					//Does SendBuf haven't No eough rooms for new coming data

	BOOL m_bNeedKeepAlive;

	CRtTimeValue m_disconn_timestamp;	//Only server use

	WORD m_keepAliveInterval;
	BYTE	m_byInstanceType;

	BOOL m_bDisableKeepaliveFlagOrNot;

	DWORD m_dwMaxBuffLen;
/***********Jobs Add at 2008.06.03 for flow control************************/
	DWORD	m_dwCurrentBW;
	DWORD	m_dwTotalSendinSec;
/***********Jobs Add at 2008.06.03 end************************/

#ifdef PRINT_CONN_DETAIL_LOG
	int m_recvNum;
#endif
};

#endif // RT_USE_OLD_CONN_WRAP

///////////////////////////////////////////
//class CConnConnectorT
///////////////////////////////////////////
template <class ClientType>
class /*RT_API_EXPORT*/ CConnConnectorT : 
			public IRtConnector, 
			public CRtReferenceControlSingleThread	//Reference tool
{
public:
	virtual void AsycConnect(
		IRtAcceptorConnectorSink *aSink,	//IConnectorSink From Upper layer
		const CRtInetAddr &aAddrPeer, 
		CRtTimeValue *aTimeout = NULL,
		CRtInetAddr *aAddrLocal = NULL)
	{
		m_pConnectorSink = aSink;
		m_aAddrPeer = aAddrPeer;

		m_pCli = new ClientType(m_connType);
		m_pCli->NeedKeepAlive(m_bNeedKeepAlive);
		m_pCli->SetConnConnector(this);
		
		//Call TP layer function
		m_pConnector->AsycConnect(
			m_pCli.ParaIn(), //CS layer CConnBase as IRtAcceptorConnectorSink to TP
			m_aAddrPeer, 
			aTimeout,
			aAddrLocal);

		if (aTimeout)
			m_pCli->ScheduleConnectTimer(*aTimeout);
	};

	//For reconnection
	void AsycReconnect(CRtTimeValue *aTimeout = NULL)
	{
		AsycConnect(
			m_pConnectorSink,
			m_aAddrPeer, 
			aTimeout);
	};

	virtual void CancelConnect()
	{
		if(m_pCli.Get())
		{
			m_pCli->CancelHandShake();
			m_pCli = NULL;
		}
		//Call TP layer function
		m_pConnector->CancelConnect();
	};
public:
	// interface IRtReferenceControl
	virtual DWORD AddReference()
	{
		return CRtReferenceControlSingleThread::AddReference();
	};

	virtual DWORD ReleaseReference()
	{
		return CRtReferenceControlSingleThread::ReleaseReference();
	};

	virtual BOOL IsConnector()
	{
		return TRUE;
	};
public:
	IRtAcceptorConnectorSink* GetConnectorSink()
	{
		return m_pConnectorSink;
	};

	IRtConnector* GetTPConnector()
	{
		return m_pConnector.Get();
	};

	CRtInetAddr GetPeerAddr()
	{
		return m_aAddrPeer;
	};
public:
	CConnConnectorT(
		IRtConnector* pConnector,
		CRtConnectionManager::CType inType,
		BOOL bNeedKeepAlive = FALSE)
	{
		m_pConnectorSink = NULL;
		RT_ASSERTE(pConnector);
		m_pConnector = pConnector;
		m_connType = inType;
		m_bNeedKeepAlive = bNeedKeepAlive;
	};

	virtual ~CConnConnectorT() 
	{};

protected:
	IRtAcceptorConnectorSink* m_pConnectorSink;	//IConnectorSink From Upper layer
	CRtAutoPtr<ClientType> m_pCli;
	CRtAutoPtr<IRtConnector> m_pConnector;	//IConnector obj from TP layer	
	CRtInetAddr m_aAddrPeer;					//For saving the IP & Port
	CRtConnectionManager::CType m_connType;
	BOOL m_bNeedKeepAlive;
};

///////////////////////////////////////////
//class CConnAcceptorSinkT
///////////////////////////////////////////
template <class ServerType>
class /*RT_API_EXPORT*/ CConnAcceptorSinkT : 
		public IRtAcceptorConnectorSink, 
		public CRtReferenceControlSingleThread	//Reference tool
{
public:
	virtual void OnConnectIndication(
		RtResult aReason,
		IRtTransport *aTrpt,
		IRtAcceptorConnectorId *aRequestId)
	{
		if(RT_SUCCEEDED(aReason))
		{
			ServerType* pSvr = new ServerType(m_pConnAcceptor->GetConnType() );
			pSvr->NeedKeepAlive(m_bNeedKeepAlive);
			
			pSvr->SetConnAcceptor(m_pConnAcceptor.ParaIn());
			pSvr->OnConnectIndication(
				aReason,
				aTrpt,
				aRequestId);
		}
		else	//Something wrong
		{
			m_pConnAcceptor->GetAcceptorSink()->OnConnectIndication(
				aReason,
				NULL,
				aRequestId);
		}
	};

public:
	void NeedKeepAlive(BOOL bNeedKeepAlive)
	{
		m_bNeedKeepAlive = bNeedKeepAlive;
	};

	void SetConnAcceptor(CConnAcceptorT<ServerType>* pConnAcceptor)
	{
		m_pConnAcceptor = pConnAcceptor;
	};

	CConnAcceptorT<ServerType>* GetConnAccepter()
	{
		return m_pConnAcceptor.Get();
	};
public:
	// interface IRtReferenceControl
	virtual DWORD AddReference()
	{
		return CRtReferenceControlSingleThread::AddReference();
	};

	virtual DWORD ReleaseReference()
	{
		return CRtReferenceControlSingleThread::ReleaseReference();
	};
public:
	CConnAcceptorSinkT()
	{
		m_pConnAcceptor = NULL;
	};

	virtual ~CConnAcceptorSinkT()
	{
		m_pConnAcceptor = NULL;
	};

protected:
	CRtAutoPtr<CConnAcceptorT<ServerType> > m_pConnAcceptor;
	BOOL m_bNeedKeepAlive;
};
		
///////////////////////////////////////////
//class CConnAcceptorT
///////////////////////////////////////////
template <class ServerType>
class /*RT_API_EXPORT*/ CConnAcceptorT : 
		public IRtAcceptor,
		public CRtReferenceControlSingleThread	//Reference tool
{
public:
	virtual RtResult StartListen(
		IRtAcceptorConnectorSink *aSink,	//IAcceptorSink From Upper layer
		const CRtInetAddr &aAddrListen)
	{ 
		RT_INFO_TRACE_THIS("CConnAcceptor::StartListen()");

		m_pAcceptorSink = aSink;

		RtResult rv = m_pAcceptor->StartListen(
			m_pConnAcceptorSink.ParaIn(), 
			aAddrListen);
		if(RT_SUCCEEDED(rv))
			m_pConnAcceptorSink->SetConnAcceptor(this);
		return rv;
	};

	virtual RtResult StopListen(RtResult aReason)
	{
		m_pConnAcceptorSink = NULL;
		if (m_pAcceptor)
			return m_pAcceptor->StopListen(aReason);
		return RT_OK;
	};
public:
	// interface IRtReferenceControl
	virtual DWORD AddReference()
	{
		return CRtReferenceControlSingleThread::AddReference();
	};

	virtual DWORD ReleaseReference()
	{
		return CRtReferenceControlSingleThread::ReleaseReference();
	};

	virtual BOOL IsConnector()
	{
		return FALSE;
	};
public:
	CConnAcceptorT(
		IRtAcceptor* pAcceptor, //TP layer Acceptor
		CConnAcceptorSinkT<ServerType> *pConnAcceptorSink, //As a AcceptorSink obj to TP layer 
		CRtConnectionManager::CType inType,
		BOOL bNeedKeepAlive = TRUE)
	{ 
		m_pAcceptor = pAcceptor; 
		m_pAcceptorSink = NULL;
		m_pConnAcceptorSink = pConnAcceptorSink;
		m_pConnAcceptorSink->NeedKeepAlive(bNeedKeepAlive);
		m_connType = inType;
	};
	virtual ~CConnAcceptorT() 
	{
		m_pAcceptor = NULL; 
		m_pAcceptorSink = NULL;
		m_pConnAcceptorSink = NULL;
	};	
public:
	IRtAcceptorConnectorSink* GetAcceptorSink()
	{
		return m_pAcceptorSink;
	}
	CRtConnectionManager::CType GetConnType() const { return m_connType; }

	IRtAcceptor* GetTPAcceptor()
	{
		return m_pAcceptor.Get();
	};
	ServerListT<ServerType>* GetServerList() const { return (ServerListT<ServerType>*)&m_serverList; }

protected:
	IRtAcceptorConnectorSink* m_pAcceptorSink;			//IAcceptorSink From Upper layer
	CRtAutoPtr<CConnAcceptorSinkT<ServerType> > m_pConnAcceptorSink;
	CRtConnectionManager::CType m_connType;
	CRtAutoPtr<IRtAcceptor> m_pAcceptor;				//IAcceptor obj from TP layer		
	ServerListT<ServerType> m_serverList;
};

///////////////////////////////////////////
//class ServerListT
///////////////////////////////////////////
template <class ServerType>
class ServerListT
{
public:
	ServerListT()
		:m_svrList(65535), m_channelId(0)
	{
		RT_ASSERTE(m_svrList.size() == 65535);
	}

	virtual ~ServerListT()
	{
		for(unsigned i = 0; i < m_svrList.size(); ++i)
		{
			if(m_svrList[i].Get())
			{
				m_svrList[i]->OnDisconnect(RT_ERROR_NETWORK_SOCKET_CLOSE, m_svrList[i]->GetLowerTransport());
				m_svrList[i] = NULL;
			}
		}
	}

	WORD AddServer(ServerType* inSvr)
	{
		RT_ASSERTE(inSvr->GetChannelId() == 0);
		CRtAutoPtr<ServerType> apSvr(inSvr);
		WORD oldChannel = m_channelId;

		for(;;)
		{
			if(oldChannel == ChannelCalculator())
			{
				RT_WARNING_TRACE_THIS("ServerListT::AddServer server list full!");
				return 0;
			}

			if(!m_svrList[m_channelId - 1].Get())
			{
				RT_INFO_TRACE_THIS("ServerListT::AddServer channel=" << m_channelId);
				m_svrList[m_channelId - 1] = apSvr;
				return m_channelId;
			}
		}
	}

	CRtAutoPtr<ServerType> GetServer(WORD inChannel) const
	{
		CRtAutoPtr<ServerType> pServer = m_svrList[inChannel - 1];
		return pServer;
	}

	void RemoveServer(WORD inChannel)
	{
		if(inChannel > 0 && m_svrList[inChannel - 1].Get())
		{
			RT_INFO_TRACE_THIS("ServerListT::RemoveServer channel=" << inChannel << " trpt=" << m_svrList[inChannel - 1].Get());
			m_svrList[inChannel - 1] = NULL;
		}
	}

	WORD ChannelCalculator()
	{
		++m_channelId;
		if(m_channelId == 0)
			m_channelId = 1;
		return m_channelId;
	}

protected:
	std::vector< CRtAutoPtr<ServerType> > m_svrList;
	WORD m_channelId;
};

#endif // CS_BASE_H

